import { Camera, director, find, game, instantiate, Node, Prefab, RenderTexture, resources, _decorator } from 'cc';
const { ccclass, property } = _decorator;

// 外部调用顺序
// 清空画布
// 添加热力点
// 渲染

export enum HeatMapLayer {
    HeatMap2D = 1 << 0,
    HeatMap3D = 1 << 1,
}

export class HiddenCanvas {
    private static instance = null;
    public static getInstance() {
        if (this.instance === null) {
            this.instance = new HiddenCanvas();
        }
        return this.instance;
    }

    public canvasSize: { width: number; height: number } = { width: 1000, height: 1000 };

    private isRender2D = false;

    private isRender3D = false;

    private ensureCanvas: Node = null;

    // Canvas 画布大小

    private content2DNode: Node = null;
    private content3DNode: Node = null;

    private camera2D: Camera = null;
    private camera3D: Camera = null;

    private renderTex: RenderTexture = null;

    public async init() {
        return new Promise<void>((resolve) => {
            // 加载 Prefab
            resources.load('prefab/HiddenCanvas', Prefab, (err, prefab) => {
                const newNode = instantiate(prefab);
                director.getScene().addChild(newNode);
                // 为啥要声明为常驻节点 ，
                // 这个画布预制 假设只在主场景使用，来回切换场景就要反复加载预制资源，预制资源有缓存，在生成节点会些不必要，会有不必要的销毁
                // 如果别的场景也需要呢

                game.addPersistRootNode(newNode);
                this.ensureCanvas = newNode;

                this.content2DNode = find('2DCanvas/Content2D', newNode);
                this.camera2D = find('2DCanvas/Camera', newNode).getComponent(Camera);
                this.camera3D = find('3DCanvas/Camera', newNode).getComponent(Camera);
                this.content3DNode = find('3DCanvas/Content3D', newNode);
                resolve();
            });
        });
    }

    // 添加2D热力点  再抽象一个层次看，如果这个是别的图形呢 命名不够确切，这是一个画布
    public add2DPoint(point: Node, intensity: number) {
        this.content2DNode.addChild(point); // 多使用？.可选链操作符
        // 如果这个 canvas预制被销毁了，或者时不存在呢
        // 按照目前的逻辑是常驻节点不会被销毁，在游戏中是一直存在的，
        // 但是按照逻辑的严谨性，如果这个父预制被销毁了，那么这个 content2DNode content3DNode camera2D camera3D的应该置为null，
    }

    // 添加3D热力点
    public add3DPoint(point: Node, intensity: number) {
        this.content3DNode.addChild(point);
    }

    // 清空2D画布
    public clear2DCanvas() {
        this.content2DNode.destroyAllChildren();
    }

    // 清空3D画布
    public clear3DCanvas() {
        this.content3DNode.destroyAllChildren();
    }

    // 渲染时有一个过程的，所以需要用标志位
    public render2D() {
        console.log('render2D========');

        this.isRender2D = true;
        this.resetRenderTexture();
        this.camera2D.targetTexture = this.renderTex;
        // 正交摄像机 的正交高度 和 画布大小的关系就是 画布的高度 /2;
        this.camera2D.orthoHeight = this.canvasSize.height / 2;
        this.isRender2D = false;

        // 外部要设置材质的贴图
        return this.renderTex;
    }

    // 这个函数的目的是获取渲染贴图

    // 从面向对象上来说 renderTex 不应该是HiddenCanvas的属性，而是摄像机返回的结果
    // 应该考虑
    public render3D() {
        this.isRender3D = true;

        this.resetRenderTexture();
        this.camera3D.targetTexture = this.renderTex;
        this.camera3D.orthoHeight = this.canvasSize.height / 2;

        this.isRender3D = false;
        return this.renderTex;
    }

    public resetCanvasSize(width: number, height: number) {
        this.canvasSize.width = width;
        this.canvasSize.height = height;
    }

    public destroy() {
        this.ensureCanvas.destroy();
    }

    private resetRenderTexture() {
        if (this.renderTex !== null) this.renderTex.destroy();
        this.renderTex = new RenderTexture();

        this.renderTex.reset({
            width: this.canvasSize.width,
            height: this.canvasSize.height,
        });
    }
}
